package vivace.model;

import java.util.*;
import java.io.*;
import javax.sound.midi.*;

public class Vivace extends Observable{

	/**
	 * Enumerator that explains the supported operations for this class.	
	 */
	public enum Action{
		ALL_CLOSED, ALL_SAVED, PROJECT_ADDED, PROJECT_CLOSED, PROJECT_ACTIVATED, PROJECT_SAVED
	}
	
	private HashMap<Integer,Project> projects;
	private Integer activeProjectKey;
	private Action action;
	
	/**
	 * @return The last performed operation for the current instance. This value can be used
	 * in the observer's update-method to see what kind of operation that was performed.
	 */
	public Action getAction() {
		return action;
	}

	/**
	 * @return The active project
	 */
	public Project getActiveProject(){
		return projects.get(activeProjectKey);
	}
	
	/**
	 * Sets the active project
	 * @param key The key of the project that should be set to active
	 */
	public void setActiveProject( Integer key ) {
		if (!key.equals(this.activeProjectKey))
			this.setChanged(); // Only update if necessary
		this.activeProjectKey = key;
		this.action = Action.PROJECT_ACTIVATED;
		this.notifyObservers( key ); 
	}

	/**
	 * @param key The key of the project
	 * @return The project with the corresponding key
	 */
	public Project getProject( Integer key ){
		return this.projects.get(key);
	}

	/**
	 * Constructor
	 */
	public Vivace(){
		this.projects = new HashMap<Integer,Project>();
		this.activeProjectKey = 0;
	}

	/**
	 * Adds an empty project to the list of projects and assigns a key to it
	 */
	public void addProject(){
		Project p = new Project();
		Integer newKey = new Integer(this.activeProjectKey+1);
		this.projects.put(newKey,p);
		p.setName("Untitled " + newKey.toString());
		this.setChanged();
		this.action = Action.PROJECT_ADDED;
		this.notifyObservers( newKey );
	}
	
	/**
	 * Reads the file specified by the file path and creates a new project from the file.
	 * The project is assigned a key and added to the list of projects.
	 * @param filePath The path to the file that should be read
	 */
	public void addProject(File file){
		
		Project p = new Project(file);
		Integer newKey = new Integer(this.activeProjectKey+1);
		this.projects.put(newKey,p);
		p.setName("Untitled " + newKey.toString());
		this.setChanged();
		this.action = Action.PROJECT_ADDED;
		this.notifyObservers( newKey );
	}
	
	/**
	 * Closes all open projects
	 */
	public void closeAll(){
		// TODO: Kolla om osparat osv...
		this.projects.clear();
		this.setChanged();
		this.action = Action.ALL_CLOSED;
		this.notifyObservers();
	}
	
	/**
	 * Closes the active project
	 */
	public void closeActive(){
		// TODO: Kolla om osparat osv...
		this.projects.remove(this.activeProjectKey);
		this.setChanged();
		this.action = Action.PROJECT_CLOSED;
		this.notifyObservers(this.activeProjectKey);
	}
	
	/**
	 * Saves all opened projects
	 */
	public void saveAll(){
		Iterator<Project> ps = this.projects.values().iterator();
		Project p;
		while(ps.hasNext()){
			p = ps.next();
			p.save();
		}
		this.setChanged();
		this.action = Action.ALL_SAVED;
		this.notifyObservers();
	}
	
	/***
	 * Saves the active project
	 */
	public void saveActive(){
		Project p = this.projects.get(this.activeProjectKey);
		p.save();
		this.setChanged();
		this.action = Action.PROJECT_SAVED;
		this.notifyObservers(this.activeProjectKey);
	}

	public String[] getMidiDeviceList() {
		MidiDevice.Info[] inf = MidiSystem.getMidiDeviceInfo();
		String[] infoStrings = new String[inf.length];
		//System.out.printf("HEj hej!!");
		if (inf.length > 0) {
			//System.out.printf("inf > 0");
			for (int index = 0; index < inf.length; index++) {
				infoStrings[index] = inf[index].toString();
			}
			return infoStrings;
		}
		return null;
	}


	
}
